package com.galfins.gogpsextracts.Glonass;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.galfins.gogpsextracts.Ephemeris;
import com.galfins.gogpsextracts.EphemerisResponse;
import com.galfins.gogpsextracts.GnssEphemeris;
import com.galfins.gogpsextracts.Iono;
import com.galfins.gogpsextracts.KeplerianModel;
import com.galfins.gogpsextracts.NavigationProducer;
import com.galfins.gogpsextracts.SatellitePosition;

import java.util.ArrayList;

import static com.galfins.gogpsextracts.GetEphFromIgmas.GetGLOEphUrl;
import static com.galfins.gogpsextracts.GetEphFromIgmas.httpGet;

/**
 * @author Lorenzo Patocchi, cryms.com
 * <p>
 * This class retrieve RINEX file on-demand from known server structures
 */
public class RinexNavigationGlonass implements NavigationProducer {
    RinexNavigationParserGlonass m_rnp = null;
    long m_ephTimestamp = 0;

    public SatellitePosition getSatPositionAndVelocities(long unixTime, double range, int satID, char satType, double receiverClockError) {
        RinexNavigationParserGlonass rnp = getRNPByTimestamp(unixTime);
        if (rnp == null)
            return null;

        if (rnp.findEph(unixTime, satID, satType) == null)
            return null;

        if (rnp != null) {
            if (rnp.isTimestampInEpocsRange(unixTime)) {
                return rnp.getSatPositionAndVelocities(unixTime, range, satID, satType, receiverClockError);
            } else {
                return null;
            }
        }

        return null;
    }

    protected RinexNavigationParserGlonass getEph() {
        ArrayList<GnssEphemeris> ephList = new ArrayList<GnssEphemeris>();
        Ephemeris.IonosphericModelProto.Builder ionoBuilder = Ephemeris.IonosphericModelProto.newBuilder();

        RinexNavigationParserGlonass rnp = null;
        String str = httpGet(GetGLOEphUrl);
        JSONObject object = JSON.parseObject(str);
        if (object != null) {
            m_ephTimestamp = object.getLong("timestamp");

            JSONObject iono = object.getJSONObject("iono");

            ionoBuilder.addAlpha(iono.getDouble("alpha0"));
            ionoBuilder.addAlpha(iono.getDouble("alpha1"));
            ionoBuilder.addAlpha(iono.getDouble("alpha2"));
            ionoBuilder.addAlpha(iono.getDouble("alpha3"));

            ionoBuilder.addBeta(iono.getDouble("beta0"));
            ionoBuilder.addBeta(iono.getDouble("beta1"));
            ionoBuilder.addBeta(iono.getDouble("beta2"));
            ionoBuilder.addBeta(iono.getDouble("beta3"));

            Ephemeris.IonosphericModelProto ionoProto = ionoBuilder.build();
            Ephemeris.IonosphericModelProto ionoProto2 = ionoBuilder.build();

            JSONArray ephArray = object.getJSONArray("eph");

            for (int i = 0; i < ephArray.size(); ++i) {
                GlonassEphemeris.Builder builder = GlonassEphemeris.newBuilder();

                JSONObject eph = ephArray.getJSONObject(i);

                builder.setSvid(eph.getInteger("prn"));

                builder.setWeek(eph.getInteger("week"));
                builder.setTocS(eph.getDouble("toc"));

                KeplerianModel.Builder model = KeplerianModel.newBuilder();
                model.setToeS(eph.getDouble("toe"));
                builder.setKeplerianModel(new KeplerianModel(model));

                builder.setTauN(eph.getFloat("tau"));
                builder.setGammaN(eph.getFloat("gammaN"));
                builder.setTk(eph.getDouble("tk"));

                builder.setX(eph.getDouble("x"));
                builder.setXv(eph.getDouble("xV"));
                builder.setXa(eph.getDouble("xA"));

                builder.setY(eph.getDouble("y"));
                builder.setYv(eph.getDouble("yV"));
                builder.setYa(eph.getDouble("yA"));

                builder.setZ(eph.getDouble("z"));
                builder.setZv(eph.getDouble("zV"));
                builder.setZa(eph.getDouble("zA"));

                builder.setFreq_num(eph.getInteger("freqNum"));
                builder.setTb(eph.getDouble("tb"));

                builder.setEn(eph.getDouble("eN"));

                ephList.add(builder.build());
            }
            EphemerisResponse ephResponse = new EphemerisResponse(ephList, ionoProto, ionoProto2);
            rnp = new RinexNavigationParserGlonass(ephResponse);
        }
        return rnp;
    }

    protected RinexNavigationParserGlonass getRNPByTimestamp(long unixTime) {
        if (m_rnp == null)
        {
            m_rnp = getEph();
        }
        return m_rnp;
    }

    @Override
    public Iono getIono(long unixTime) {
        RinexNavigationParserGlonass rnp = getRNPByTimestamp(unixTime);
        if (rnp != null) return rnp.getIono(unixTime);
        return null;
    }
}

